package org.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.example.controller.back.UmsRecodes;
import org.example.mapper.UmsRuleMapper;
import org.example.pojo.UmsRule;
import org.example.pojo.UmsRuleRelate;
import org.example.mapper.UmsRuleRelateMapper;
import org.example.service.IUmsRuleRelateService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.service.IUmsRuleService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wy
 * @since 2023-10-05
 */
@Service
public class UmsRuleRelateServiceImpl extends ServiceImpl<UmsRuleRelateMapper, UmsRuleRelate> implements IUmsRuleRelateService {
    @Resource
    UmsRuleRelateMapper relateMapper;

    @Resource
    IUmsRuleService ruleService;

    @Resource
    UmsRuleMapper ruleMapper;
    @Override
    public Object getResult(List<String> causes) {
        StringBuilder causeIds = new StringBuilder();
        for(String cause : causes){
            UmsRule rule = ruleMapper.selectByName(cause);
            causeIds.append(rule.getId()).append(",");
        }
        causeIds = new StringBuilder(causeIds.substring(0, causeIds.length() - 1));
        UmsRuleRelate umsRuleRelate = relateMapper.selectByCause(causeIds.toString());

        if(umsRuleRelate != null){
            Integer result = umsRuleRelate.getResult();
            QueryWrapper<UmsRule> wrapper = new QueryWrapper<>();
            wrapper.eq("id", result);
            wrapper.eq("active", 1);
            return ruleService.page(new Page<>(umsRuleRelate.getPageNo(),
                    umsRuleRelate.getPageSize()), wrapper);
        }

        return null;
    }

    @Override
    public boolean reverseIsOrNo(String result, List<String> causes) {
        UmsRule rule = ruleMapper.selectByName(result);
        List<Integer> causeIds = getCauseIds(causes);
        QueryWrapper<UmsRuleRelate> wrapper = new QueryWrapper<>();
        wrapper.eq("result", rule.getId());
        List<UmsRuleRelate> list = this.list(wrapper);

        List<Integer> ruleIds = new ArrayList<>();
        for(UmsRuleRelate ruleRelate : list){
            String[] split = ruleRelate.getCause().split(",");
            for(String s : split){
                if(!ruleIds.contains(Integer.valueOf(s))){
                    ruleIds.add(Integer.valueOf(s));
                }
            }
        }

        return ruleIds.containsAll(causeIds);
    }

    @Override
    public List<UmsRecodes> getReverseRecodes(String result, List<String> causes){
        boolean isOr = false;
        List<UmsRecodes> recodes = new ArrayList<>();
        UmsRule rule = ruleMapper.selectByName(result);
        Stack<Integer> stack = new Stack<>();
        stack.push(rule.getId());
        List<Integer> causeIds = getCauseIds(causes);
        Set<Integer> ruleIds = new HashSet<>();
        while (!stack.isEmpty()){//深度优先 自顶向下
            Integer pop = stack.pop();
            QueryWrapper<UmsRuleRelate> wrapper = new QueryWrapper<>();
            wrapper.eq("result", pop);
            wrapper.eq("active", 1);
            List<UmsRuleRelate> list = this.list(wrapper);

            for(UmsRuleRelate ruleRelate : list){
                UmsRecodes recodeOne = new UmsRecodes();
                recodeOne.setResult(ruleMapper.selectById(pop).getName());
                String[] split = ruleRelate.getCause().split(",");
                List<String> names = new ArrayList<>();
                for(String s : split){
                    Integer id = Integer.valueOf(s);
                    if(!ruleIds.contains(id)){
                        stack.push(id);
                        names.add(ruleMapper.selectById(id).getName() + "  ");
                    }
                    ruleIds.add(id);
                    if(ruleIds.containsAll(causeIds)){
                        isOr = true;
                        break;
                    }
                }

                recodeOne.setCause(names);
                recodes.add(recodeOne);
            }
        }

        UmsRecodes umsRecodes = new UmsRecodes();
        umsRecodes.setResult("失败");
        if(isOr){
            umsRecodes.setResult("成功");
        }
        recodes.add(umsRecodes);
        return recodes;
    }

    @Override
    public List<UmsRecodes> getReverseRecodes(String result, Set<Integer> set) {
        List<UmsRecodes> recodes = new ArrayList<>();
        UmsRule rule = ruleMapper.selectByName(result);
        Stack<Integer> stack = new Stack<>();
        stack.push(rule.getId());
        Set<Integer> ruleIds = new HashSet<>();

        StringBuilder final_result = new StringBuilder(rule.getName() + "的所有特征为: ");
        while (!stack.isEmpty()) {//深度优先 自顶向下
            Integer pop = stack.pop();
            set.add(pop);
            QueryWrapper<UmsRuleRelate> wrapper = new QueryWrapper<>();
            wrapper.eq("result", pop);
            wrapper.eq("active", 1);
            List<UmsRuleRelate> list = this.list(wrapper);

            for (UmsRuleRelate ruleRelate : list) {
                UmsRecodes recodeOne = new UmsRecodes();
                recodeOne.setResult(ruleMapper.selectById(pop).getName());
                String[] split = ruleRelate.getCause().split(",");
                List<String> names = new ArrayList<>();
                for (String s : split) {
                    Integer id = Integer.valueOf(s);
                    if (!ruleIds.contains(id)) {
                        stack.push(id);
                        String name = ruleMapper.selectById(id).getName();
                        names.add(name + "  ");
                        final_result.append(name).append(' ');
                    }
                    ruleIds.add(id);
                }

                recodeOne.setCause(names);
                recodes.add(recodeOne);
            }
        }

        UmsRecodes umsRecodes = new UmsRecodes();
        umsRecodes.setResult(final_result.toString());
        recodes.add(umsRecodes);
        set.addAll(ruleIds);
        return recodes;
    }

    @Override
    public List<UmsRecodes> getBidrection(List<String> right, String left) {
        List<UmsRecodes> result = new ArrayList<>();
        Set<Integer> right_set = new HashSet<>();
        Set<Integer> left_set = new HashSet<>();
        List<UmsRecodes> details = this.getDetails(right, right_set);
        List<UmsRecodes> reverseRecodes = this.getReverseRecodes(left, left_set);
        UmsRecodes recodes = new UmsRecodes();
        recodes.setResult("------正向推理------");
        result.add(recodes);
        result.addAll(details);

        recodes = new UmsRecodes();
        recodes.setResult("------逆向推理------");
        result.add(recodes);
        result.addAll(reverseRecodes);

        recodes = new UmsRecodes();
        recodes.setResult("失败匹配");
        if(left_set.containsAll(right_set) && right_set.containsAll(left_set)) recodes.setResult("成功匹配");

        result.add(recodes);
        return result;
    }

    @Override
    public boolean updateByRuleId(Integer ruleId) {
        QueryWrapper<UmsRuleRelate> wrapper = new QueryWrapper<>();
        wrapper.eq("result", ruleId);
        wrapper.eq("active", 1);
        List<UmsRuleRelate> list = this.list(wrapper);
        for(UmsRuleRelate li : list){
            li.setActive(0);
            this.updateById(li);
        }

        wrapper = new QueryWrapper<>();
        wrapper.like("cause", String.valueOf(ruleId));
        wrapper.eq("active", 1);
        list = this.list(wrapper);
        for(UmsRuleRelate li : list){
            li.setActive(0);
            this.updateById(li);
        }

        return true;
    }

    @Override
    public boolean updateByIdTest(UmsRuleRelate ruleRelate) {
        UmsRuleRelate byId = this.getById(ruleRelate.getId());
        List<Integer> list = new ArrayList<>();
        list.add(byId.getResult());
        String[] split = byId.getCause().split(",");
        for (String s : split){
            list.add(Integer.valueOf(s));
        }

        for (Integer li : list){
            UmsRule byId1 = ruleService.getById(li);
            if(byId1 == null || byId1.getActive() == 0){
                return false;
            }
        }
        this.updateById(ruleRelate);
        return true;
    }

    @Override
    public Object list(UmsRuleRelate rule) {
        // 如果 有name传过来 就按照name 模糊查询
        QueryWrapper<UmsRuleRelate> wrapper = new QueryWrapper<>();
        if(rule.getResult() != null) {
            wrapper.like("result",rule.getResult());
        }
        if(rule.getActive() !=null) {
            wrapper.eq("active",rule.getActive());
        }

        // 如果分页返回 IPage 如果不分页 返回 List
        if(rule.getWithPage() == 1) {
            return this.page(new Page<>(rule.getPageNo(),rule.getPageSize()),wrapper);
        } else {
            return this.list(wrapper);
        }
    }

    @Override
    public boolean batchdel(Integer[] ids) {
        List<Integer> list = new ArrayList<>(ids.length);
        Collections.addAll(list,ids);
        UmsRuleRelate rule = new UmsRuleRelate();
        rule.setActive(0);
        UpdateWrapper<UmsRuleRelate> wrapper = new UpdateWrapper<>();
        wrapper.in("id",list);
        return this.update(rule,wrapper);
    }

    @Override
    public List<UmsRecodes> getDetails(List<String> causes, Set<Integer> set) {
        List<List<Integer>> recodes = new ArrayList<>();

        List<Integer> listCauseIds = getCauseIds(causes);
        set.addAll(listCauseIds);
        boolean is = true;
        while (is){
            is = false;
            Integer[] integers = Arrays.copyOfRange(listCauseIds.toArray(), 0, listCauseIds.size(), Integer[].class);
            ArrayList<ArrayList<Integer>> subList = getSubList(integers);
            for(ArrayList<Integer> sub : subList) {
                QueryWrapper<UmsRuleRelate> wrapper = new QueryWrapper<>();
                String cause = "";
                for(Integer e : sub){
                    cause += e + ",";
                }
                wrapper.eq("cause", cause.substring(0, cause.length() - 1));
                wrapper.eq("active", 1);
                UmsRuleRelate one = getOne(wrapper);
                if (one != null) {
                    is = true;
                    Integer result = one.getResult();
                    set.add(result);
                    List<Integer> recode = new ArrayList<>(sub);
                    recode.add(result);
                    recodes.add(recode);
                    HashSet<Integer> setCauses = new HashSet<>(listCauseIds);
                    HashSet<Integer> setSub = new HashSet<>(sub);
                    setCauses.removeAll(setSub);
                    setCauses.add(result);
                    listCauseIds = new ArrayList<>(setCauses);
                    break;
                }
            }
        }

        return getRecodesName(recodes);
    }

    private List<UmsRecodes> getRecodesName(List<List<Integer>> recodes){
        List<UmsRecodes> lists = new ArrayList<>();
        for(List<Integer> recode : recodes){
            UmsRecodes recodes_re = new UmsRecodes();
            List<String> list = new ArrayList<>();
            for(Integer id : recode){
                UmsRule rule = ruleMapper.selectById(id);
                list.add(rule.getName() + "  ");
            }
            recodes_re.setResult(list.get(list.size() - 1));
            list.remove(list.get(list.size() - 1));
            recodes_re.setCause(list);

            lists.add(recodes_re);
        }

        return lists;
    }


    //cause name --> id
    private List<Integer> getCauseIds(List<String> causes){
        List<Integer> causeIds = new ArrayList<>();
        for(String cause : causes){
            UmsRule rule = ruleMapper.selectByName(cause);
            if(rule != null) causeIds.add(rule.getId());
        }

        return causeIds;
    }

    /**
     * 获取所有子集
     */
    private ArrayList<ArrayList<Integer>> getSubList(Integer[] arr) {
        ArrayList<ArrayList<Integer>> allList = new ArrayList<>();
        int size = 1 << arr.length;// 2^n次方
        for (int mark = 0; mark < size; mark++) {
            ArrayList<Integer> aList = new ArrayList<>();
            for (int i = 0; i < arr.length; i++) {
                /* 重要：这句是最重要的代码:是 0-7 分别与运算 1，2，4
                 * 000 001 010 011 100 101 110 111
                 *
                 */
                if ((mark & (1 << i)) != 0) {
                    aList.add(arr[i]);
                }
            }
            Collections.sort(aList);
            if(aList.size() > 1) allList.add(aList);
        }
        return allList;
    }

}
